DynamoDB に大量データを Promise.all で書き込み、読込みしてみる
はじめに
おはようございます、もきゅりんです。
Shall we promise all ?
タイトルのような検証があったのですが、 結果、不要になったためお焚き上げとして ブログにしておきました。
やること
このブログでやることは、以下です。
AWS SDK for JavaScript V2, V3(V2互換API) を使い、単一の既存テーブルに対して、パーティションキー(ハッシュキー)を用いて
- 大量データを投入する
- 投入した大量データを読み込む
GitHubリポジトリ にサンプルコードをあげていますので、ご自由に検証下さい。
各ディレクトリで npm install
の上、ts-node
コマンドで実行します。
背景として
DDB への大量データの投入ですが、新規テーブルで対応する場合、 DynamoDBのテーブルにCSVファイルから一括でデータをimportしてみた で対応するも良いでしょうし、新規だろうと既存テーブルだろうと、 Lambda(python3.6)を使って大量のデータをDynamoDBに追加するときはbatch_writerが便利 なら わざわざ Promise all や for…of などを利用することなく比較的スムーズにデータ投入できます。
でも、 今回は Node.js を使って、かつ、既存テーブルを対象としたかった のです。。
そして、 BatchWriteItem
では最大16MBデータまたは最大25個のアイテムの書き込みまたは削除操作の制限、 BatchGetItem
では最大16MBデータまたは最大100個のアイテムの読み込みが仕様制限になります。
そのため Promise.all を入用とした次第です。
ちなみに余談なのですが、CloudFormation を使った DDB テーブルへ csv を使ったデータ投入において、Excelファイルから csv ファイルにした場合、 BOM (Byte Order Mark) のせいでそのままテンプレートを利用するとコケます。
(このテンプレートの例外処理のエラーメッセージだと何も原因がわからないので、自分はとりあえず基底クラス Exception を指定しました)
Excel ファイルから csvファイルを作成する場合、 Lambda のコード箇所を下記のように修正して利用しましょう。
" ## for row in csv.DictReader(codecs.getreader('utf-8')(obj)):", " for row in csv.DictReader(codecs.getreader('utf-8-sig')(obj)):", " if len(batch) >= batch_size:", " write_to_dynamo(batch)", " batch.clear()",
残りは、いくつか留意点などだけ記載しておきます。
その他
使用される認証情報の優先順位が異なるので、v2, v3 との切り替え時に困惑しました。
- JavaScript V3 for SDK へのコードの移行 - AWS SDK for JavaScript のパス2を参考に v3 に対応していたのですが、batch(get | write)item では、値にタイプを指定する必要がありました。
そのため、サンプルデータの json データの形式も異なります。
ちなみに、json データは、https://json-generator.com/ でテキトーに生成しています。
- 書き込み対応のファイルでは、for…of と Promise.all の両方を記載しています。
数百レコード程度ではDDBの負荷も大したことはないので、 Promise.all でも支障ないと思いますが、数千レコードになってくるとスロットリングする可能性もあると 広島 からアドバイスを貰いました。
データ量によっては for…of を選択して実行します。
以上です。
どなたかの参考になれば幸いです。